#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QNetworkDatagram>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 首先创建出socket对象
    socket = new QUdpSocket(this);  // 使用对象树进行释放
    // 设置窗口标题
    this->setWindowTitle("服务器");
    // 必须要先连接信号槽再绑定，因为一旦绑定成功了，就可能有数据过来，而没有对应的处理函数，不然那个数据就浪费了
    // 连接信号槽
    connect(socket, &QUdpSocket::readyRead, this, &Widget::processRequest);
    // 绑定
    bool ret = socket->bind(QHostAddress::Any, 8080);
    // 绑定失败
    if(!ret)
    {
        // 弹出一个对话框
        QMessageBox::critical(this, "服务器出错", socket->errorString());
        return;
    }
    // 此时绑定成功，就完成对应的接受数据后的处理函数
}

Widget::~Widget()
{
    delete ui;
}

// 这个函数完成的逻辑，就是服务器最核心的逻辑了
void Widget::processRequest()
{
    // 1. 读取请求并解析
    QNetworkDatagram requestData = socket->receiveDatagram();
    QString request = requestData.data();  // 获取数据包内部持有的数据，返回一个 QByteArray，但是QString能接受
    // 2. 根据请求计算响应，由于此时是回显服务器，响应不需要计算，请求即是响应
    QString response = process(request);
    // 3. 把响应写回给客户端
    // 构建响应，响应的对端存储在发送来的 QNetworkDatagram 上
    QNetworkDatagram responseData(response.toUtf8(), requestData.senderAddress(), requestData.senderPort());
    socket->writeDatagram(responseData);
    // 把这次交互的信息，回显到界面上
    QString log = "[" + requestData.senderAddress().toString() + ":" + QString::number(requestData.senderPort()) + "]: "
                  + "req: " + request + "; resp: " + response;
    ui->listWidget->addItem(log);
}

QString Widget::process(const QString &request)
{
    // 由于当前是回显服务器，响应和请求完全一样
    // 对于一个成熟的商业服务器，这里请求、响应的计算过程是非常复杂的(业务逻辑)
    return request;
}

